﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;

namespace SuperiorCommon
{
    public class WeiXinHelper
    {
        private static string sToken = System.Configuration.ConfigurationManager.AppSettings["weixintoken"].Trim();//与微信那边填写的token一致
        private static string sEncodingAESKey = System.Configuration.ConfigurationManager.AppSettings["weixinaeskey"].Trim();
        private static string SSLCertPath = "cert/apiclient_cert.p12";//安全证书位置
        private static string SSLCertPassword = "1535452741";//证书密码

        public static bool VerifySignature(string sTimeStamp, string sNonce, string sSigture)
        {
            int ret = WXBizMsgCrypt.VerifySignature(sToken, sTimeStamp, sNonce, "", sSigture);
            if (ret != 0)
            {
                LogManger.Instance.WriteLog("验证微信消息真实性失败，信息：sTimeStamp=" + sTimeStamp + ";sNonce=" + sNonce + ";sSigture=" + sSigture + "返回码:" + ret);
                return false;
            }
            return true;
        }

        public static string GetOpenIdStr(string appid, string secret, string code)
        {
            LogManger.Instance.WriteLog("appid:" + appid + ",secret:" + secret + ",code=" + code);
            string url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
            return WeiXinHelper.Get(url);
        }
        public static string GetAccessToken(string appid, string secret)
        {
            string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret + "";
            return WeiXinHelper.Get(url);
        }
        public static string GetToken(string appid, string secret, string code)
        {
            string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
            return WeiXinHelper.Get(url);
        }

        public static string GetUserInfo(string token, string oid)
        {
            return WeiXinHelper.Get("https://api.weixin.qq.com/sns/userinfo?access_token=" + token + "&openid=" + oid + "&lang=zh_CN");
        }

        public static byte[] GetQrCode(string accessToken, string path, int width)
        {
            var parmModel = new { path = path, width = width };
            string requestUrl = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=" + accessToken;
            return PostDataToUrl_QrCode(Newtonsoft.Json.JsonConvert.SerializeObject(parmModel), requestUrl);
        }

       
        /// <summary>
        /// Aes解密
        /// </summary>
        /// <param name="str">需要解密的字符串</param>
        /// <param name="key">密钥,长度不够时空格补齐,超过时从左截取</param>
        /// <param name="iv">偏移量,长度不够时空格补齐,超过时从左截取</param>
        /// <param name="keyLenth">秘钥长度,16 24 32</param>
        /// <param name="aesMode">解密模式</param>
        /// <param name="aesPadding">填充方式</param>
        /// <returns></returns>
        public static string AesDecode(string str, string key, string iv, int keyLenth = 16, CipherMode aesMode = CipherMode.CBC, PaddingMode aesPadding = PaddingMode.PKCS7)
        {
            if (!new List<int> { 16, 24, 32 }.Contains(keyLenth))
            {
                return null;//密钥的长度，16位密钥 = 128位，24位密钥 = 192位，32位密钥 = 256位。
            }
            var oldBytes = Convert.FromBase64String(str);
            var bKey = new Byte[keyLenth];
            Array.Copy(Convert.FromBase64String(key.PadRight(keyLenth)), bKey, keyLenth);
            var bIv = new Byte[16];
            Array.Copy(Convert.FromBase64String(iv.PadRight(16)), bIv, 16);

            var rijalg = new RijndaelManaged
            {
                Mode = aesMode,
                Padding = aesPadding,
                Key = bKey,
                IV = bIv,
            };
            var decryptor = rijalg.CreateDecryptor(rijalg.Key, rijalg.IV);
            var rtByte = decryptor.TransformFinalBlock(oldBytes, 0, oldBytes.Length);
            return Encoding.UTF8.GetString(rtByte);
        }



        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认，否则打不开
            return true;
        }
        public static string Post(string xml, string url, bool isUseCert, int timeout)
        {
            System.GC.Collect();//垃圾回收，回收没有正常关闭的http连接
            string result = "";//返回结果
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;
            StreamReader sr = null;
            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                }
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "POST";
                request.Timeout = timeout * 1000;
                //设置POST的数据类型和长度
                request.ContentType = "text/xml";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                request.ContentLength = data.Length;
                //是否使用证书
                if (isUseCert)
                {
                    string path = HttpContext.Current.Request.PhysicalApplicationPath;
                    X509Certificate2 cert = new X509Certificate2(path + SSLCertPath, SSLCertPassword);
                    request.ClientCertificates.Add(cert);
                }
                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(data, 0, data.Length);
                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();
                //获取服务端返回数据
                sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd().Trim();
            }
            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (sr != null)
                {
                    sr.Close();
                }
                if (reqStream != null)
                {
                    reqStream.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        public static string Get(string url)
        {
            System.GC.Collect();
            Stream instream = null;
            StreamReader sr = null;
            HttpWebResponse response = null;
            HttpWebRequest request = null;
            Encoding encoding = Encoding.UTF8;

            string content = string.Empty;
            // 准备请求...
            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                }
                // 设置参数
                request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "GET";

                //发送请求并获取相应回应数据
                response = request.GetResponse() as HttpWebResponse;
                instream = response.GetResponseStream();
                sr = new StreamReader(instream, encoding);
                //返回结果网页（html）代码
                content = sr.ReadToEnd();
            }
            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
                if (sr != null)
                {
                    sr.Close();
                }
                if (instream != null)
                {
                    instream.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return content;
        }

        /// <summary>
        /// 转换字节流并调用方法
        /// </summary>
        /// <param name="data"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static byte[] PostDataToUrl_QrCode(string data, string url)
        {
            Encoding encoding = Encoding.GetEncoding("utf-8");

            byte[] bytesToPost = encoding.GetBytes(data);

            return PostDataToUrl_QrCode(bytesToPost, url);
        }

        /// <summary>
        /// 转换字节流并调用方法
        /// </summary>
        /// <param name="data"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public string PostDataToUrl(string data, string url)
        {
            Encoding encoding = Encoding.GetEncoding("utf-8");

            byte[] bytesToPost = encoding.GetBytes(data);

            return PostDataToUrl(bytesToPost, url);
        }

        /// <summary>
        /// 执行链接得到返回信息
        /// </summary>
        /// <param name="data"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        private static string PostDataToUrl(byte[] data, string url)
        {
            string stringResponse = string.Empty;

            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            #region 创建httpWebRequest对象
            WebRequest webRequest = WebRequest.Create(url);
            HttpWebRequest httpRequest = webRequest as HttpWebRequest;
            #endregion

            #region 填充httpWebRequest的基本信息
            httpRequest.ContentType = "application/x-www-form-urlencoded";
            httpRequest.Method = "POST";
            httpRequest.Timeout = 1000 * 10;

            #endregion


            Stream requestStream = null;
            try
            {
                #region 填充要post的内容
                httpRequest.ContentLength = data.Length;
                requestStream = httpRequest.GetRequestStream();
                requestStream.Write(data, 0, data.Length);
                requestStream.Close();
                #endregion

                #region 发送post请求到服务器并读取服务器返回信息
                Stream responseStream = null;

                try
                {
                    responseStream = httpRequest.GetResponse().GetResponseStream();

                    using (StreamReader responseReader =
                        new StreamReader(responseStream, Encoding.GetEncoding("utf-8")))
                    {
                        stringResponse = responseReader.ReadToEnd();
                    }
                    responseStream.Close();
                }
                catch (Exception e)
                {
                    stringResponse = e.Message;
                }
                #endregion

                #region 读取服务器返回信息

                #endregion
            }
            catch { }
            return stringResponse;
        }

        private static byte[] PostDataToUrl_QrCode(byte[] data, string url)
        {
            byte[] res = null;

            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            #region 创建httpWebRequest对象
            WebRequest webRequest = WebRequest.Create(url);
            HttpWebRequest httpRequest = webRequest as HttpWebRequest;
            #endregion

            #region 填充httpWebRequest的基本信息
            httpRequest.ContentType = "application/x-www-form-urlencoded";
            httpRequest.Method = "POST";
            httpRequest.Timeout = 1000 * 10;

            #endregion


            Stream requestStream = null;
            try
            {
                #region 填充要post的内容
                httpRequest.ContentLength = data.Length;
                requestStream = httpRequest.GetRequestStream();
                requestStream.Write(data, 0, data.Length);
                requestStream.Close();
                #endregion

                #region 发送post请求到服务器并读取服务器返回信息
                Stream responseStream = null;

                try
                {
                    responseStream = httpRequest.GetResponse().GetResponseStream();
                    res = StreamToBytes(responseStream);

                }
                catch (Exception e)
                {

                }
                #endregion

                #region 读取服务器返回信息

                #endregion
            }
            catch { }
            return res;
        }

        ///将数据流转为byte[]
        public static byte[] StreamToBytes(Stream stream)
        {
            List<byte> bytes = new List<byte>();
            int temp = stream.ReadByte();
            while (temp != -1)
            {
                bytes.Add((byte)temp);
                temp = stream.ReadByte();
            }
            return bytes.ToArray();
        }

        // 检验消息的真实性，并且获取解密后的明文
        // @param sMsgSignature: 签名串，对应URL参数的msg_signature
        // @param sTimeStamp: 时间戳，对应URL参数的timestamp
        // @param sNonce: 随机串，对应URL参数的nonce
        // @param sPostData: 密文，对应POST请求的数据
        // @param sMsg: 解密后的原文，当return返回0时有效
        // @return: 成功0，失败返回对应的错误码
        public static int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg)
        {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, "");
            return wxcpt.DecryptMsg(sMsgSignature, sTimeStamp, sNonce, sPostData, ref sMsg);
        }

        //将企业号回复用户的消息加密打包
        // @param sReplyMsg: 企业号待回复用户的消息，xml格式的字符串
        // @param sTimeStamp: 时间戳，可以自己生成，也可以用URL参数的timestamp
        // @param sNonce: 随机串，可以自己生成，也可以用URL参数的nonce
        // @param sEncryptMsg: 加密后的可以直接回复用户的密文，包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
        //						当return返回0时有效
        // return：成功0，失败返回对应的错误码
        public static int EncryptMsg(string sAppID, string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg)
        {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sAppID);
            return wxcpt.EncryptMsg(sReplyMsg, sTimeStamp, sNonce, ref sEncryptMsg);
        }

        public static string GetXmlText(string ToUserName, string FromUserName, string Content)
        {
            string xml = "<xml>";
            xml += "<ToUserName><![CDATA[" + ToUserName + "]]></ToUserName>";
            xml += "<FromUserName><![CDATA[" + FromUserName + "]]></FromUserName>";
            xml += "<CreateTime>" + ToolManager.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";
            xml += "<MsgType><![CDATA[text]]></MsgType>";
            xml += "<Content><![CDATA[" + Content + "]]></Content>";
            xml += "</xml>";
            return xml;
        }

        public static string GetXmlImage(string ToUserName, string FromUserName, string MediaId)
        {
            string xml = "<xml>";
            xml += "<ToUserName><![CDATA[" + ToUserName + "]]></ToUserName>";
            xml += "<FromUserName><![CDATA[" + FromUserName + "]]></FromUserName>";
            xml += "<CreateTime>" + ToolManager.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";
            xml += "<MsgType><![CDATA[image]]></MsgType>";
            xml += "<Image>";
            xml += "<MediaId><![CDATA[" + MediaId + "]]></MediaId>";
            xml += "</Image>";
            xml += "</xml>";
            return xml;
        }

        public static string GetXmlNews(string ToUserName, string FromUserName, string Title, string Description, string PicUrl, string Url)
        {
            string xml = "<xml>";
            xml += "<ToUserName><![CDATA[" + ToUserName + "]]></ToUserName>";
            xml += "<FromUserName><![CDATA[" + FromUserName + "]]></FromUserName>";
            xml += "<CreateTime>" + ToolManager.ConvertDateTimeInt(DateTime.Now) + "</CreateTime>";
            xml += "<MsgType><![CDATA[news]]></MsgType>";
            xml += "<ArticleCount>1</ArticleCount>";
            xml += "<Articles>";
            xml += "<item>";
            xml += "<Title><![CDATA[" + Title + "]]></Title>";
            xml += "<Description><![CDATA[" + Description + "]]></Description>";
            xml += "<PicUrl><![CDATA[" + PicUrl + "]]></PicUrl>";
            xml += "<Url><![CDATA[" + Url + "]]></Url>";
            xml += "</item>";
            xml += "</Articles>";
            xml += "</xml>";
            return xml;
        }

    }
    //微信请求类
    public class RequestXML
    {
        private string toUserName;
        /// <summary>
        /// 消息接收方微信号，一般为公众平台账号微信号
        /// </summary>
        public string ToUserName
        {
            get { return toUserName; }
            set { toUserName = value; }
        }

        private string fromUserName;
        /// <summary>
        /// 消息发送方微信号
        /// </summary>
        public string FromUserName
        {
            get { return fromUserName; }
            set { fromUserName = value; }
        }

        private string createTime;
        /// <summary>
        /// 创建时间
        /// </summary>
        public string CreateTime
        {
            get { return createTime; }
            set { createTime = value; }
        }

        private string msgType;
        /// <summary>
        /// 信息类型 地理位置:location,文本消息:text,消息类型:image
        /// </summary>
        public string MsgType
        {
            get { return msgType; }
            set { msgType = value; }
        }

        private string content;
        /// <summary>
        /// 信息内容
        /// </summary>
        public string Content
        {
            get { return content; }
            set { content = value; }
        }

        private string location_X;
        /// <summary>
        /// 地理位置纬度
        /// </summary>
        public string Location_X
        {
            get { return location_X; }
            set { location_X = value; }
        }

        private string location_Y;
        /// <summary>
        /// 地理位置经度
        /// </summary>
        public string Location_Y
        {
            get { return location_Y; }
            set { location_Y = value; }
        }

        private string scale;
        /// <summary>
        /// 地图缩放大小
        /// </summary>
        public string Scale
        {
            get { return scale; }
            set { scale = value; }
        }

        private string label;
        /// <summary>
        /// 地理位置信息
        /// </summary>
        public string Label
        {
            get { return label; }
            set { label = value; }
        }

        private string picUrl;
        /// <summary>
        /// 图片链接，开发者可以用HTTP GET获取
        /// </summary>
        public string PicUrl
        {
            get { return picUrl; }
            set { picUrl = value; }
        }

        private string _eventType;
        public string EventType
        {
            get { return _eventType; }
            set { _eventType = value; }
        }
        private string _key;
        public string Key
        {
            get { return _key; }
            set { _key = value; }
        }
        private string _MsgID;
        public string MsgID
        {
            get { return _MsgID; }
            set { _MsgID = value; }
        }
        private string _Status;
        public string Status
        {
            get { return _Status; }
            set { _Status = value; }
        }
    }
}
